package cn.fintecher.pangolin.service.business.service;

import cn.fintecher.pangolin.common.enums.*;
import cn.fintecher.pangolin.common.exception.BadRequestException;
import cn.fintecher.pangolin.common.model.DepartmentModel;
import cn.fintecher.pangolin.common.model.UserModel;
import cn.fintecher.pangolin.common.response.LoginResponse;
import cn.fintecher.pangolin.common.utils.BeanUtils;
import cn.fintecher.pangolin.common.utils.Constants;
import cn.fintecher.pangolin.common.utils.RepositoryUtil;
import cn.fintecher.pangolin.common.utils.ZWDateUtil;
import cn.fintecher.pangolin.entity.elastic.BaseCase;
import cn.fintecher.pangolin.entity.elastic.HistoryCases;
import cn.fintecher.pangolin.entity.mysql.*;
import cn.fintecher.pangolin.service.business.model.DebtBatchNumber;
import cn.fintecher.pangolin.service.business.model.request.*;
import cn.fintecher.pangolin.service.business.model.response.*;
import cn.fintecher.pangolin.service.business.repository.elasticsearch.BaseCaseRespository;
import cn.fintecher.pangolin.service.business.repository.elasticsearch.HistoryCasesRespository;
import cn.fintecher.pangolin.service.business.repository.jparepository.AssistCaseRepository;
import cn.fintecher.pangolin.service.business.repository.jparepository.CaseInfoRepository;
import cn.fintecher.pangolin.service.business.repository.jparepository.ProcessApplicationRepository;
import cn.fintecher.pangolin.service.business.repository.jparepository.UserRepository;
import cn.fintecher.pangolin.service.business.task.CheckCaseTask;
import com.google.common.collect.Lists;
import com.querydsl.core.BooleanBuilder;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.valuecount.InternalValueCount;
import org.elasticsearch.search.aggregations.metrics.valuecount.ValueCountAggregationBuilder;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.matchPhraseQuery;

@Service
public class CaseInfoService {

    @Autowired
    private CaseInfoRepository caseInfoRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private BaseCaseRespository baseCaseRespository;

    @Autowired
    private HistoryCasesRespository historyCasesRespository;

    @Autowired
    private ModelMapper modelMapper;

    @Autowired
    private BaseService baseService;

    @Autowired
    private AssistCaseRepository assistCaseRepository;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    private ProcessApplicationRepository processApplicationRepository;

    @Autowired
    private CheckCaseTask checkCaseTask;

    /**
     * @Author wangxiangdong
     * @Description 案件停催
     * @Date 2019/9/9 15:49
     **/
    @Transactional
    public void stopCase(String[] ids) {
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(QCaseInfo.caseInfo.id.in(ids));
        List<CaseInfo> caseInfoList = new ArrayList<>();
        Iterator<CaseInfo> iterator = caseInfoRepository.findAll(booleanBuilder).iterator();
        while (iterator.hasNext()) {
            CaseInfo caseInfo = iterator.next();
            caseInfo.setStopTime(ZWDateUtil.getNowDateTime());
            caseInfo.setCaseDataStatus(CaseDataStatus.PAUSE);
            caseInfoList.add(caseInfo);
        }
        List<AssistCase> assistCaseList = Lists.newArrayList(assistCaseRepository.findAll(QAssistCase.assistCase.caseId.in(ids).
                and(QAssistCase.assistCase.assistStatus.eq(AssistStatus.ASSIST_COLLECTING)).or(QAssistCase.assistCase.assistStatus.eq(AssistStatus.ASSIST_WAIT_ASSIGN))));
        assistCaseList.forEach(assistCase -> {
            assistCase.setAssistStatus(AssistStatus.ASSIST_COMPLETED);
        });
        List<ProcessApplication> processApplicationList = Lists.newArrayList(processApplicationRepository.findAll(QProcessApplication.processApplication.caseId.in(ids).and(QProcessApplication.processApplication.approvalStage.eq(ApprovalStage.WAIT_APPROVAL)
                .or(QProcessApplication.processApplication.approvalStage.eq(ApprovalStage.BEING_APPROVAL)))));
        processApplicationList.forEach(processApplication -> {
            processApplication.setApprovalStage(ApprovalStage.APPROVAL_CANCEL);
            processApplication.getProcessFlowNodes().forEach(processFlowNode -> {
                processFlowNode.setApprovedResult(ApprovalResult.APPROVED_REJECT);
                processFlowNode.setApprovalStatus(ApprovalStatus.APPROVED_COMPLETED);
            });
        });
        processApplicationRepository.saveAll(processApplicationList);
        assistCaseRepository.saveAll(assistCaseList);
        caseInfoRepository.saveAll(caseInfoList);
    }

    /**
     * @Author wangxiangdong
     * @Description 案件复催
     * @Date 2019/9/9 15:49
     **/
    public void backCollectCasePool(String[] caseIds) {
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(QCaseInfo.caseInfo.id.in(caseIds));
        List<CaseInfo> caseInfoList = new ArrayList<>();
        Iterator<CaseInfo> iterator = caseInfoRepository.findAll(booleanBuilder).iterator();
        while (iterator.hasNext()) {
            CaseInfo caseInfo = iterator.next();
            if (Objects.nonNull(caseInfo.getCurrentCollector())) {
                User user = userRepository.getOne(caseInfo.getCurrentCollector().getId());
                if (Objects.equals(user.getStatus(), UserStatus.WORKING)) {
                    caseInfo.setStopTime(null);
                    caseInfo.setCaseDataStatus(CaseDataStatus.IN_POOL);
                } else {
                    caseInfo.setStopTime(null);
                    caseInfo.setCaseDataStatus(null);
                    caseInfo.setDepartment(caseInfo.getCurrentCollector().getDepartment());
                }
            }
            caseInfoList.add(caseInfo);
        }
        caseInfoRepository.saveAll(caseInfoList);
    }

    /**
     * @Author wangxiangdong
     * @Description 退案操作
     * @Date 2019/9/9 18:23
     **/
    @Transactional
    public void changeRetireCases(CaseReturnRequest caseReturnRequest, UserModel userModel) {
        List<HistoryCases> historyCasesArrayList = new ArrayList<>();
        List<BaseCase> baseCaseList = new ArrayList<>();
        List<CaseInfo> caseInfoList = Lists.newArrayList(caseInfoRepository.findAll(QCaseInfo.caseInfo.id.in(caseReturnRequest.getCaseIds())));
        List<BaseCase> baseCases = Lists.newArrayList(baseCaseRespository.findAllById(caseReturnRequest.getCaseIds()));
        Map<String, CaseInfo> caseInfoMap = caseInfoList.stream().collect(Collectors.toMap(CaseInfo::getId, caseInfo -> caseInfo));
        for (BaseCase baseCase : baseCases) {
            CaseInfo caseInfo = caseInfoMap.get(baseCase.getId());
            HistoryCases historyCases = new HistoryCases();
            if(Objects.nonNull(caseInfo)){
                historyCases.setDepartment(caseInfo.getDepartment());
                historyCases.setCaseType(caseInfo.getCaseType());
                historyCases.setCurrentCollector(caseInfo.getCurrentCollector());
            }
            BeanUtils.copyPropertiesIgnoreNull(baseCase, historyCases);
            historyCases.setHistoryCaseStatus(HistoryCaseStatus.RETIRE_POOL);
            historyCases.setOperateTime(ZWDateUtil.getNowDateTime());
            historyCases.setOperator(userModel.getRealName());
            baseCaseList.add(baseCase);
            historyCasesArrayList.add(historyCases);
        }
        List<AssistCase> assistCaseList = Lists.newArrayList(assistCaseRepository.findAll(QAssistCase.assistCase.caseId.in(caseReturnRequest.getCaseIds()).
                and(QAssistCase.assistCase.assistStatus.eq(AssistStatus.ASSIST_COLLECTING)).or(QAssistCase.assistCase.assistStatus.eq(AssistStatus.ASSIST_WAIT_ASSIGN))));
        assistCaseList.forEach(assistCase -> {
            assistCase.setAssistStatus(AssistStatus.ASSIST_COMPLETED);
        });
        List<ProcessApplication> processApplicationList = Lists.newArrayList(processApplicationRepository.findAll(QProcessApplication.processApplication.caseId.in(caseReturnRequest.getCaseIds()).and(QProcessApplication.processApplication.approvalStage.eq(ApprovalStage.WAIT_APPROVAL)
                .or(QProcessApplication.processApplication.approvalStage.eq(ApprovalStage.BEING_APPROVAL)))));
        processApplicationList.forEach(processApplication -> {
            processApplication.setApprovalStage(ApprovalStage.APPROVAL_CANCEL);
            processApplication.getProcessFlowNodes().forEach(processFlowNode -> {
                processFlowNode.setApprovedResult(ApprovalResult.APPROVED_REJECT);
                processFlowNode.setApprovalStatus(ApprovalStatus.APPROVED_COMPLETED);
            });
        });
        if(processApplicationList.size()>0){
            processApplicationRepository.saveAll(processApplicationList);
        }
        if(assistCaseList.size()>0){
            assistCaseRepository.saveAll(assistCaseList);
        }
        if(caseInfoList.size()>0){
            caseInfoRepository.deleteAll(caseInfoList);
        }
        baseCaseRespository.deleteAll(baseCaseList);
        historyCasesRespository.saveAll(historyCasesArrayList);
    }

    /**
     * @Author wangxiangdong
     * @Description 查询在催案件池批次号
     * @Date 2019/9/16 10:58
     **/
    public List<String> getBatchNumber(String poolName, UserModel userModel) {
        if (Objects.equals(userModel.getIsCheck(), BaseSelect.YES)) {
            return caseInfoRepository.getBatchNumber(poolName, userModel.getPrincipalIds());
        } else {
            return caseInfoRepository.getBatchNumber(poolName);
        }
    }

    /**
     * @Author wangxiangdong
     * @Description 刷新退案时间
     * @Date 2019/9/16 10:58
     */
    public void updateCaseEndDate(UpdateCaseEndDateRequest updateCaseEndDateRequest, UserModel userByToken) {
        List<CaseInfo> caseInfoList = new ArrayList<>();
        List<BaseCase> baseCaseList = new ArrayList<>();
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        QCaseInfo qCaseInfo = QCaseInfo.caseInfo;
        if (StringUtils.isNotBlank(updateCaseEndDateRequest.getBatchNumber())) {
            booleanBuilder.and(qCaseInfo.batchNumber.eq(updateCaseEndDateRequest.getBatchNumber()));
            boolQueryBuilder.must(QueryBuilders.termsQuery("batchNumber.keyword", updateCaseEndDateRequest.getBatchNumber()));
        }
        if (StringUtils.isNotBlank(updateCaseEndDateRequest.getCaseId())) {
            booleanBuilder.and(qCaseInfo.id.eq(updateCaseEndDateRequest.getCaseId()));
            boolQueryBuilder.must(QueryBuilders.termsQuery("id.keyword", updateCaseEndDateRequest.getCaseId()));
        }

        for (CaseInfo caseInfo : caseInfoRepository.findAll(booleanBuilder)) {
            caseInfo.setEndCaseDate(updateCaseEndDateRequest.getEndCaseDate());
            caseInfo.setUpdateDate(ZWDateUtil.getNowDateTime());
            caseInfo.setUpdatePersonName(userByToken.getRealName());
            caseInfoList.add(caseInfo);
        }
        for (BaseCase baseCase : baseCaseRespository.search(boolQueryBuilder)) {
            baseCase.setEndCaseDate(updateCaseEndDateRequest.getEndCaseDate());
            baseCaseList.add(baseCase);
        }
        caseInfoRepository.saveAll(caseInfoList);
        baseCaseRespository.saveAll(baseCaseList);
    }

    public PersonalResponse getPersonalById(String personalId) {
        BaseCase baseCase = baseCaseRespository.findById(personalId).orElseThrow(() -> new BadRequestException(null, "personal", "personal.not.exist"));
        PersonalResponse personalResponse = new PersonalResponse();
        BeanUtils.copyPropertiesIgnoreNull(baseCase, personalResponse);
        return personalResponse;
    }

    /**
     * @Author wangxiangdong
     * @Description 修改进件以及客户信息
     * @Date 2019/9/17 11:05
     **/
    @Transactional
    public void updateCaseMessage(CaseUpdateMessageRequest caseUpdateMessageRequest) {
        CaseInfo caseInfo = caseInfoRepository.getOne(caseUpdateMessageRequest.getCaseInfoMessage().getId());
        BeanUtils.copyPropertiesIgnoreNull(caseUpdateMessageRequest.getCaseInfoMessage(), caseInfo);
        caseInfo.setPhone(caseUpdateMessageRequest.getPersonalMessage().getPhone());
        caseInfo.setAddress(caseUpdateMessageRequest.getPersonalMessage().getHomeAddr());
        BaseCase baseCase = baseCaseRespository.findById(caseUpdateMessageRequest.getPersonalMessage().getId()).orElseThrow(() -> new BadRequestException(null, "personal", "personal.not.exist"));
        BeanUtils.copyPropertiesIgnoreNull(caseUpdateMessageRequest.getPersonalMessage(), baseCase);
        BeanUtils.copyPropertiesIgnoreNull(caseUpdateMessageRequest.getCaseInfoMessage(), baseCase);
        caseInfoRepository.save(caseInfo);
        baseCaseRespository.save(baseCase);
    }

    public Page<CaseInfoStatusResponse> caseCollectionStatus(CaseCollectionStatusRequest request, String token, Pageable pageable) {
        LoginResponse userSessionByToken = baseService.getUserSessionByToken(token);
        UserModel userModel = userSessionByToken.getUserModel();
        BooleanBuilder booleanBuilder = request.generateQueryBuilder();
        if (Objects.equals("INNER", request.getCasePool())) {
            QCaseInfo qCaseInfo = QCaseInfo.caseInfo;
            booleanBuilder.and(qCaseInfo.caseDataStatus.notIn(CaseDataStatus.SETTLT, CaseDataStatus.REDUCE));
            if (Objects.equals(userSessionByToken.getUserModel().getIsManage().name(), ManagementType.YES.name())) {
                booleanBuilder.and(qCaseInfo.currentCollector.department.departCode.like(StringUtils.join(userSessionByToken.getDepartmentModel().getDepartCode(), "%")));
            } else {
                booleanBuilder.and(qCaseInfo.currentCollector.id.eq(userSessionByToken.getUserModel().getId()));
            }
            booleanBuilder.and(qCaseInfo.caseDataStatus.in(CaseDataStatus.IN_POOL, CaseDataStatus.SETTLT, CaseDataStatus.REDUCE));
            if (userModel.getIsCheck().equals(BaseSelect.YES)) {
                booleanBuilder.and(qCaseInfo.principalId.in(userModel.getPrincipalIds()));
            }
            Page<CaseInfo> caseInfoPage = caseInfoRepository.findAll(booleanBuilder, pageable);
            return caseInfoPage.map(caseInfo -> modelMapper.map(caseInfo, CaseInfoStatusResponse.class));
        } else if (Objects.equals("LEAVE_CASE", request.getCasePool())) {
            QCaseInfo qCaseInfo = QCaseInfo.caseInfo;
            booleanBuilder.and(qCaseInfo.caseDataStatus.notIn(CaseDataStatus.SETTLT, CaseDataStatus.REDUCE));
            if (Objects.equals(userSessionByToken.getUserModel().getIsManage().name(), ManagementType.YES.name())) {
                booleanBuilder.and(qCaseInfo.currentCollector.department.departCode.like(StringUtils.join(userSessionByToken.getDepartmentModel().getDepartCode(), "%")));
            } else {
                booleanBuilder.and(qCaseInfo.currentCollector.id.eq(userSessionByToken.getUserModel().getId()));
            }
            booleanBuilder.and(qCaseInfo.leaveFlag.eq(CaseLeaveFlag.HAS_LEAVE));
            if (userModel.getIsCheck().equals(BaseSelect.YES)) {
                booleanBuilder.and(qCaseInfo.principalId.in(userModel.getPrincipalIds()));
            }
            Page<CaseInfo> caseInfoPage = caseInfoRepository.findAll(booleanBuilder, pageable);
            return caseInfoPage.map(caseInfo -> modelMapper.map(caseInfo, CaseInfoStatusResponse.class));
        } else if (Objects.equals("ASSIST_CASE", request.getCasePool())) {
            QAssistCase qAssistCase = QAssistCase.assistCase;
            if (Objects.equals(userSessionByToken.getUserModel().getIsManage().name(), ManagementType.YES.name())) {
                booleanBuilder.and(qAssistCase.assistCollector.department.departCode.like(StringUtils.join(userSessionByToken.getDepartmentModel().getDepartCode(), "%")));
            } else {
                booleanBuilder.and(qAssistCase.assistCollector.id.eq(userSessionByToken.getUserModel().getId()));
            }
            if (userModel.getIsCheck().equals(BaseSelect.YES)) {
                booleanBuilder.and(qAssistCase.principalId.in(userModel.getPrincipalIds()));
            }
            Page<AssistCase> caseInfoPage = assistCaseRepository.findAll(booleanBuilder, pageable);
            return caseInfoPage.map(assistCase -> modelMapper.map(assistCase, CaseInfoStatusResponse.class));
        } else {
            throw new BadRequestException(null, "", "case.pool.unkonw");
        }

    }

    public void searchDebtBatchNumber(CollectionDebtRequest request, DebtInfoResponse debtInfoResponse, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        String index;
        if (Objects.equals(request.getType(), CasePool.INPOOLCASE)) {
            index = Constants.BASE_CASE;
        } else {
            index = Constants.HISTORY_CASES;
        }
        BoolQueryBuilder qb = request.generateQueryBuilder();
        baseService.spliceBuilder(qb, userModel);
        TermsAggregationBuilder principal = AggregationBuilders.terms("principalName").field("principalName.keyword");
        TermsAggregationBuilder operBatchNumberBuilder = AggregationBuilders.terms("operBatchNumber").field("batchNumber.keyword");
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withIndices(index)
                .withTypes(index)
                .withSearchType(SearchType.DEFAULT)
                .withQuery(qb)
                .addAggregation(principal.subAggregation(operBatchNumberBuilder)).build();
        Aggregations aggregations = elasticsearchTemplate.query(searchQuery, response -> response.getAggregations());
        Map<String, Aggregation> map = aggregations.asMap();
        if (map.get("principalName") instanceof StringTerms) {
            StringTerms principalCount = (StringTerms) map.get("principalName");
            for (StringTerms.Bucket bucket : principalCount.getBuckets()) {
                String principalName = bucket.getKeyAsString();
                DebtBatchNumber debtOperBatchNumber = new DebtBatchNumber();
                debtOperBatchNumber.setPrincipalName(principalName);
                StringTerms operBatchNumbers = bucket.getAggregations().get("operBatchNumber");
                for (StringTerms.Bucket bucket1 : operBatchNumbers.getBuckets()) {
                    String operBatchNumber = bucket1.getKeyAsString();
                    debtOperBatchNumber.getBatchNumber().add(operBatchNumber);
                }
                debtInfoResponse.getDeptInfo().add(debtOperBatchNumber);
            }
        }
    }

    public List<AccountInfoResponse> searchDebtCardInfo(CollectionDebtRequest request) {
        BoolQueryBuilder qb = request.generateQueryBuilder();
        if (StringUtils.isNoneBlank(request.getBatchNumber())) {
            qb.must(matchPhraseQuery("batchNumber.keyword", request.getBatchNumber()));
        }
        List<AccountInfoResponse> accountInfoResponseList = new ArrayList<>();
        if (Objects.equals(request.getType(), CasePool.INPOOLCASE)) {
            List<BaseCase> baseCaseList = IterableUtils.toList(baseCaseRespository.search(qb));
            for (BaseCase baseCase : baseCaseList) {
                AccountInfoResponse accountInfoResponse = new AccountInfoResponse();
                BeanUtils.copyPropertiesIgnoreNull(baseCase, accountInfoResponse);
                accountInfoResponse.setCaseId(baseCase.getId());
                accountInfoResponseList.add(accountInfoResponse);
            }
        } else {
            List<HistoryCases> historyCasesList = IterableUtils.toList(historyCasesRespository.search(qb));
            for (HistoryCases historyCases : historyCasesList) {
                AccountInfoResponse accountInfoResponse = new AccountInfoResponse();
                BeanUtils.copyPropertiesIgnoreNull(historyCases, accountInfoResponse);
                accountInfoResponse.setCaseId(historyCases.getId());
                accountInfoResponseList.add(accountInfoResponse);
            }
        }
        return accountInfoResponseList;
    }

    /**
     * @Author wangxiangdong
     * @Description 查询共债数量
     * @Date 2019/11/2 14:39
     **/
    public Map<String, Long> searchDebtCaseCount(String index, CollectionDebtRequest request, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        BoolQueryBuilder qb = request.generateQueryBuilder();
        baseService.spliceBuilder(qb, userModel);
        TermsAggregationBuilder principal = AggregationBuilders.terms("principalId").field("principalId.keyword");
        ValueCountAggregationBuilder countAggregationBuilder = AggregationBuilders.count("count").field("id.keyword");
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withIndices(index)
                .withTypes(index)
                .withSearchType(SearchType.DEFAULT)
                .withQuery(qb)
                .addAggregation(principal.subAggregation(countAggregationBuilder)).build();
        Aggregations aggregations = elasticsearchTemplate.query(searchQuery, response -> response.getAggregations());
        Map<String, Aggregation> map = aggregations.asMap();
        Map<String, Long> mapBuff = new HashMap<>();
        mapBuff.put("samePrincipal", Long.valueOf("0"));
        mapBuff.put("differentPrincipal", Long.valueOf("0"));
        if (map.get("principalId") instanceof StringTerms) {
            StringTerms principalCount = (StringTerms) map.get("principalId");
            long sameConut = 0;
            long diffCount = 0;
            for (StringTerms.Bucket bucket : principalCount.getBuckets()) {
                String keyAsString = bucket.getKeyAsString();
                Map<String, Aggregation> subaggregationMap = bucket.getAggregations().getAsMap();
                long caseCount = ((InternalValueCount) subaggregationMap.get("count")).getValue();
                if (Objects.equals(keyAsString, request.getPrincipalId())) {
                    sameConut += caseCount;
                } else {
                    diffCount += caseCount;
                }
            }
            mapBuff.put("samePrincipal", sameConut);
            mapBuff.put("differentPrincipal", diffCount);
        }
        return mapBuff;
    }

    public void changeCaseType(ChangeCaseTypeRequest changeCaseTypeRequest, UserModel userModel) {
        List<CaseInfo> caseInfoList = Lists.newArrayList(caseInfoRepository.findAllById(changeCaseTypeRequest.getCaseIds()));
        List<AssistCase> assistCases = new ArrayList<>();
        List<ProcessApplication> applications = new ArrayList<>();
        caseInfoList.forEach(caseInfo -> {
            caseInfo.setCaseType(changeCaseTypeRequest.getCaseType());
            caseInfo.setCaseDataStatus(CaseDataStatus.CIRCULATION);
            if (Objects.nonNull(caseInfo.getCurrentCollector())) {
                caseInfo.setDepartment(caseInfo.getCurrentCollector().getDepartment());
                caseInfo.setCurrentCollector(null);
            }
            caseInfo.setUpdateDate(ZWDateUtil.getNowDateTime());
            caseInfo.setUpdatePersonName(userModel.getRealName());

            //判断协催案件
            if (changeCaseTypeRequest.getCaseType().equals(CaseType.VISIT_CASE)) { //转为外访
                Iterable<AssistCase> iterable = assistCaseRepository.findAll(QAssistCase.assistCase.caseId.eq(caseInfo.getId())
                        .and(QAssistCase.assistCase.assistStatus.in(AssistStatus.ASSIST_WAIT_ASSIGN, AssistStatus.ASSIST_COLLECTING)));
                List<AssistCase> assistCaseList = IterableUtils.toList(iterable);
                if (!assistCaseList.isEmpty()) {
                    assistCaseList.forEach(e -> {
                        e.setAssistStatus(AssistStatus.ASSIST_CANCEL);
                        e.setOperator(userModel.getId());
                        e.setOperatorTime(ZWDateUtil.getNowDateTime());
                    });
                    assistCases.addAll(assistCaseList);
                }

                Iterable<ProcessApplication> applicationIterable = processApplicationRepository.findAll(QProcessApplication.processApplication.caseId.eq(caseInfo.getId()).and(QProcessApplication.processApplication.approvalStage.eq(ApprovalStage.WAIT_APPROVAL)
                        .or(QProcessApplication.processApplication.approvalStage.eq(ApprovalStage.BEING_APPROVAL))));
                List<ProcessApplication> processApplications = IterableUtils.toList(applicationIterable);
                if (!processApplications.isEmpty()) {
                    processApplications.forEach(e -> {
                        e.setApprovalStage(ApprovalStage.APPROVAL_CANCEL);
                        e.getProcessFlowNodes().forEach(processFlowNode -> {
                            processFlowNode.setApprovedResult(ApprovalResult.APPROVED_REJECT);
                            processFlowNode.setApprovalStatus(ApprovalStatus.APPROVED_COMPLETED);
                        });
                    });
                    applications.addAll(processApplications);
                }
            }
        });
        RepositoryUtil.saveData(caseInfoRepository, caseInfoList);
        RepositoryUtil.saveData(assistCaseRepository, assistCases);
        RepositoryUtil.saveData(processApplicationRepository, applications);
    }

    /**
     * 检查案件是否存在协催申请和协催案件
     */
    public CheckCaseResponse checkCase(ChangeCaseTypeRequest request) {
        CheckCaseResponse response = new CheckCaseResponse();
        List<String> caseIds = request.getCaseIds();
        if (!caseIds.isEmpty()) {
            List<CompletableFuture<CheckCaseResponse>> futures = new ArrayList<>();
            int pageSize = 50;
            int pageNumber = (int) Math.ceil((double) caseIds.size() / (double) pageSize);
            for (int i = 0; i < pageNumber; i++) {
                List<String> list = caseIds.stream().skip(i * pageSize).limit(pageSize).collect(Collectors.toList());
                CompletableFuture<CheckCaseResponse> task = checkCaseTask.doTask(list);
                futures.add(task);
            }
            List<CheckCaseResponse> responses = new ArrayList<>();
            try {
                for (CompletableFuture<CheckCaseResponse> future : futures) {
                    responses.add(future.get());
                }
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
            List<String> caseNumbers1 = new ArrayList<>();
            List<String> caseNumbers2 = new ArrayList<>();
            responses.forEach(e -> {
                caseNumbers1.addAll(e.getCaseNumbers1());
                caseNumbers2.addAll(e.getCaseNumbers2());
            });
            response.setCaseNumbers1(caseNumbers1);
            response.setCaseNumbers2(caseNumbers2);
        }
        return response;
    }

    /**
     * 流转待分配查询
     */
    public Page<DistributedCaseResponse> getAllCirculationCase(CirculationCaseRequest request, Pageable pageable, String token) {
        UserModel userModel = baseService.getUserByToken(token);
        DepartmentModel departmentModel = baseService.getDepartmentByToken(token);
        BooleanBuilder builder = request.getBuilder();
        if (Objects.equals(userModel.getIsManage(), BaseSelect.YES)) {
            builder.and(QCaseInfo.caseInfo.department.departCode.like(StringUtils.join(departmentModel.getDepartCode(), "%")));
        } else {
            builder.and(QCaseInfo.caseInfo.currentCollector.id.eq(userModel.getId()));
        }
        if (userModel.getIsCheck().equals(BaseSelect.YES)) {
            builder.and(QCaseInfo.caseInfo.principalId.in(userModel.getPrincipalIds()));
        }
        Page<CaseInfo> page = caseInfoRepository.findAll(builder, pageable);
        return page.map(e -> modelMapper.map(e, DistributedCaseResponse.class));
    }
}
